package com.ai.bitcoin.schedule.task;

import com.ai.bitcoin.bean.BccAllInfo;
import com.ai.bitcoin.constant.Bcc;
import com.ai.bitcoin.jpa.dao.BccCrawlOtherUrlMaintenanceDao;
import com.ai.bitcoin.jpa.dao.BccVisitCrawlDao;
import com.ai.bitcoin.jpa.dao.GithubInfoCrawlDao;
import com.ai.bitcoin.jpa.dao.RedditInfoCrawlDao;
import com.ai.bitcoin.jpa.entity.*;
import com.ai.bitcoin.jpa.service.*;
import com.ai.bitcoin.redis.service.BccRedisService;
import com.ai.bitcoin.serialize.BeanSerial;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Jason
 * @date 2018/3/29
 **/
@Slf4j
@Component
public class DetailBasicInfoTask extends AbstractTask {
    @Autowired
    BccScoreRuleService bccScoreRuleService;
    @Autowired
    BccBasicInfoService bccBasicInfoService;
    @Autowired
    BccRedisService bccRedisService;
    @Autowired
    BccTradeService bccTradeService;
    @Autowired
    BccRankService bccRankService;
    @Autowired
    BccBatchService bccBatchService;
    @Autowired
    BccRankHisService BccRankHisService;
    @Autowired
    BccBasicInfoCrawlService bccBasicInfoCrawlService;
    @Autowired
    BccShowControlService bccShowControlService;
    @Autowired
    BccPriceInfoService bccPriceInfoService;
    @Autowired
    BccInfoEditService bccInfoEditService;
    @Autowired
    BccDailyInfoService bccDailyInfoService;
    @Autowired
    BccBasicDataCrawlService bccBasicDataCrawlService;

    @Autowired
    BccCrawlOtherUrlMaintenanceDao bccCrawlOtherUrlMaintenanceDao;

    @Autowired
    RedditInfoCrawlDao redditInfoCrawlDao;

    @Autowired
    BccVisitCrawlDao bccVisitCrawlDao;

    @Autowired
    GithubInfoCrawlDao githubInfoCrawlDao;

    @Autowired
    DailyInfoTask dailyInfoTask;

    @Override
    public void execute() {
        long start;
        List<BccBatch> batchList = bccBatchService.findByBatchTypeAndBatchStateOrderByBatchTimeEndDesc(Bcc.BathType.CRAWL_BASIC_INFO, Bcc.BathState.CRAWL_DONE);
        if (batchList.size() == 0) {
            log.info("爬虫太慢了还没有新批次数据");
            return;
        }
        BccBatch latestBccBatch = batchList.get(0);
        if (batchList.size() > 1) {
            log.info("爬虫爬取数据真快呀，我都错过了{}个版本了,把这些版本状态更新为:{}", batchList.size() - 1, Bcc.BathState.EXPIRE);
            for (int i = 1; i < batchList.size(); i++) {
                BccBatch bccBatch = batchList.get(i);
                bccBatch.setBatchState(Bcc.BathState.EXPIRE);
                log.info("", BeanSerial.Bean2Json(bccBatch).toString());
                bccBatchService.save(bccBatch);
            }
        }

        String latestBatchNo = latestBccBatch.getBatchNo();
        if (StringUtils.isEmpty(latestBatchNo)) {
            log.info("糟糕，batch为空，不能执行,{}", BeanSerial.Bean2Json(latestBccBatch).toString());
            return;
        }

        log.info("开始处理，batchNo:{}", BeanSerial.Bean2Json(latestBccBatch).toString());

        log.info("清理未发布的脏数据");
        start = System.currentTimeMillis();
        bccBasicInfoService.deleteNoPublish();
        log.info("清理未发布的脏数据，consume:{}ms", (System.currentTimeMillis() - start));

        log.info("开始将爬取的数据入库到bcc_basic_info表");
        start = System.currentTimeMillis();
        Sort sort = new Sort(Sort.Direction.ASC, "bccId");
        Pageable pageable = PageRequest.of(0, pageSizeDb, sort);
        Page<BccBasicInfoCrawl> page = bccBasicInfoCrawlService.findByBatchNo(latestBatchNo, pageable);
        List<BccBasicInfoCrawl> bccBasicInfoCrawls = page.getContent();

        int pageNum = page.getTotalPages();
        log.info("总共页数:{},每页大小:{}", pageNum, pageSizeDb);
        for (int i = 0; i < pageNum; i++) {
            log.info("第{}页", i);
            if (i != 0) {
                pageable = PageRequest.of(i, pageSizeDb, sort);
                page = bccBasicInfoCrawlService.findByBatchNo(latestBatchNo, pageable);
                bccBasicInfoCrawls = page.getContent();
            }
            saveList2Info(bccBasicInfoCrawls);
        }
        log.info("爬取的数据入库到bcc_basic_info表结束，consume:{}ms", (System.currentTimeMillis() - start));

        log.info("开始换版,batchNo:{}", latestBatchNo);
        start = System.currentTimeMillis();
        BccBasicInfo bccBasicInfo = bccBasicInfoService.findOneByRecordState(Bcc.RecordState.UN_PUBLISH);
        if (bccBasicInfo != null)
            bccBasicInfoService.update2Publish(latestBatchNo);
        log.info("换版完成，consume:{}ms", (System.currentTimeMillis() - start));

        log.info("cache basicInfo to redis");
        start = System.currentTimeMillis();
        List<BccBasicInfo> list = bccBasicInfoService.findByRecordState(Bcc.RecordState.PUBLISH);
        JSONArray bccList = new JSONArray();
        BccShowControl bccShowControl = bccShowControlService.findByBccIdAndShowType(Bcc.BCC_DEDAULT, Bcc.ShowType.BasicInfo);
        for (BccBasicInfo aList : list) {
            bccList.add(aList.getBccId());
            bccRedisService.cacheBasic2Redis(aList.getBccId(), getShowInfo(getAllInfo(aList).getJsonObject(), bccShowControl));
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                log.info("", e);
            }
        }
        bccRedisService.cacheBccList2Redis(bccList);
        log.info("cache basicInfo to redis done,consume:{}", (System.currentTimeMillis() - start));

        //更新批次状态
        log.info("更新批次状态,bath={},{}->{}", latestBatchNo, Bcc.BathState.CRAWL_DONE, Bcc.BathState.HANDLE_DONE);
        latestBccBatch.setBatchState(Bcc.BathState.HANDLE_DONE);
        bccBatchService.save(latestBccBatch);
    }


    private BccAllInfo getAllInfo(BccBasicInfo basicInfo) {
        String bccId = basicInfo.getBccId();
        List<BccInfoEdit> list = bccInfoEditService.findByBccId(bccId);
        List<BccDailyInfo> dailyInfos = bccDailyInfoService.findByBccIdAndRecordState(basicInfo.getBccId(), Bcc.RecordState.PUBLISH);
        BccDailyInfo bccDailyInfo = null;
        if (dailyInfos.size() == 1)
            bccDailyInfo = dailyInfos.get(0);
        BccPriceInfo priceInfo = null;
        List<BccBatch> list1 = bccBatchService.findByBatchTypeAndBatchStateOrderByBatchTimeEndDesc(Bcc.BathType.CRAWL_PRICE_INFO, Bcc.BathState.HANDLE_DONE);
        if (list1.size() > 0) {
            BccBatch bccBatch = list1.get(0);
            List<BccPriceInfo> priceInfos = bccPriceInfoService.findByBccIdAndBatchNo(bccId, bccBatch.getBatchNo());
            if (priceInfos.size() > 0) {
                priceInfo = priceInfos.get(0);
            }
        }
        return new BccAllInfo(basicInfo, bccDailyInfo, priceInfo, list, null, null);
    }

    @Transactional
    public void saveList2Info(List<BccBasicInfoCrawl> bccBasicInfoCrawls) {
        if (bccBasicInfoCrawls.size() == 0) {
            return;
        }

        BccBasicInfoCrawl bccBasicInfoCrawl;
        for (BccBasicInfoCrawl bccBasicInfoCrawl1 : bccBasicInfoCrawls) {
            BccBasicInfo bccBasicInfo = new BccBasicInfo();
            bccBasicInfoCrawl = bccBasicInfoCrawl1;
            String bccId = bccBasicInfoCrawl.getBccId();
            if (StringUtils.isEmpty(bccId)) {
                continue;
            }
            BeanUtils.copyProperties(bccBasicInfoCrawl, bccBasicInfo);
            bccBasicInfo.setRecordState(Bcc.RecordState.UN_PUBLISH);
            bccBasicInfo.setOfficialSiteUrlCount(StringUtils.isEmpty(bccBasicInfo.getOfficialSiteUrl()) ? 0 : 1);
            Date icoTime = bccBasicInfo.getIcoEndTime();
            if (icoTime != null) {
                bccBasicInfo.setIcoToNowDay((int) TimeUnit.DAYS.convert(new Date().getTime() - icoTime.getTime(), TimeUnit.MILLISECONDS));
            }
            else {
                bccBasicInfo.setIcoToNowDay(getDefaultDay());
            }
            Date onlineTime = bccBasicInfo.getOnlineTime();
            if (onlineTime != null) {
                bccBasicInfo.setOnlineToNowDay((int) TimeUnit.DAYS.convert(new Date().getTime() - onlineTime.getTime(), TimeUnit.MILLISECONDS));
            }
            else {
                bccBasicInfo.setOnlineToNowDay(getDefaultDay());
            }
            log.info("bccId:{}", bccBasicInfo.getBccId());
            bccBasicInfoService.save(bccBasicInfo);
        }
    }

    private int getDefaultDay() {
        return 3 * 60;
    }
}
